package org.altervista.cp.thinjdbc;

import java.sql.Blob;
import java.sql.Clob;
import java.sql.Date;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.Calendar;

import org.altervista.cp.thinjdbc.util.LogHelper;
import org.altervista.cp.thinjdbc.wrappers.PreparedStatement;
import org.altervista.cp.thinjdbc.wrappers.SQLRuntimeException;

public abstract class Query<T> {

	private static final LogHelper logger = new LogHelper(Query.class);

	protected abstract T executeActivated();

	public void clearParameters() {
		if (_psw != null) {
			_psw.clearParameters();
		}
	}

	public PreparedStatement getPreparedStatement() {
		return _psw;
	}

	public void setParameter(int index, Object value) {
		activate();
		int jdbcType = Types.OTHER;
		if (value instanceof java.util.Date) {
			if (!(value instanceof Timestamp || value instanceof Date)) {
				value = new Timestamp(((java.util.Date) value).getTime());
			}
			jdbcType = Types.TIMESTAMP;
		} else if (value instanceof Calendar) {
			value = new Timestamp(((Calendar) value).getTime().getTime());
			jdbcType = Types.TIMESTAMP;
		} else if (value instanceof Number) {
			jdbcType = Types.NUMERIC;
		} else if (value instanceof Blob) {
			jdbcType = Types.BLOB;
		} else if (value instanceof Clob) {
			jdbcType = Types.CLOB;
		} else if (value == null) {
			jdbcType = Types.NULL;
		}
		_psw.setObject(index, value, jdbcType);
	}

	public T excecute() {
		logger.debug("executing query: {0}", this);
		activate();
		return executeActivated();
	}

	public String toString() {
		return _psw == null ? null : _psw.toString();
	}

	public String getSQLString() {
		return _sql;
	}

	protected Query(String sql) {
		_sql = sql;
	}

	private void activate() {
		Session session = Session.current();
		if (session == null) {
			throw new SQLRuntimeException("No session is open at the moment",
					null);
		}
		if (_psw == null) {
			_psw = session.getConnection().prepareStatement(_sql);
		}
		session.addOpenQuery(this);
	}

	private String _sql;
	private PreparedStatement _psw;
}
